package com.hugang.juc.volatiledemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * volatile关键字
 * 1、验证volatile的保证可见性
 * 1）、资源类MyData的number属性未加volatile关键字，则不存在可见性，程序结果应该为main线程一直处于死循环状态；
 * 2）、资源类MyData的number属性加volatile关键字，保证可见性，则main线程感知到了number变了，因此结束循环；
 * 2、验证volatile不保证原子性
 *
 * @author hg
 * @date 2020/8/24 14:38
 */
public class VolatileDemo {

    public static void main(String[] args) {
        noAtomicByVolatile();

    }

    /**
     * 不保证原子性，使用AtomicXxx解决
     */
    private static void noAtomicByVolatile() {
        MyData myData = new MyData();

        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    //myData的number属性值+1
                    myData.addOne();
                    myData.addAtomic();
                }
            }, String.valueOf(i)).start();
        }

        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + " ---> number:" + myData.number);
        System.out.println(Thread.currentThread().getName() + " ---> atomicInteger:" + myData.atomicInteger);
    }

    /**
     * 保证可见性
     */
    private static void seeOkByVolatile() {
        MyData myData = new MyData();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " ---> come in");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.addTo60();
            System.out.println(Thread.currentThread().getName() + " ---> update number value");
        }, "aaa").start();

        while (myData.number == 0) {

        }
        System.out.println(Thread.currentThread().getName() + " ---> mission over");
    }
}

class MyData {
    volatile int number = 0;

    public void addTo60() {
        this.number = 60;
    }

    public void addOne() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    public void addAtomic(){
        atomicInteger.getAndIncrement();
    }
}
